package org.xiaoyu.rpc.postProcessor;

import com.xiaoyu.beans.BeansException;
import com.xiaoyu.beans.PropertyValues;
import com.xiaoyu.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.xiaoyu.stereotype.Component;
import org.xiaoyu.rpc.Invoker;
import org.xiaoyu.rpc.client.ClientHandler;
import org.xiaoyu.rpc.common.annotations.RpcReference;
import org.xiaoyu.rpc.common.annotations.RpcService;
import org.xiaoyu.rpc.common.constant.SystemPropertiesKey;
import org.xiaoyu.rpc.common.extension.ExtensionLoader;
import org.xiaoyu.rpc.common.url.URL;
import org.xiaoyu.rpc.factory.SingletonFactory;
import org.xiaoyu.rpc.protocol.Protocol;
import org.xiaoyu.rpc.proxy.ProxyFactory;
import org.xiaoyu.rpc.registry.Registry;
import org.xiaoyu.rpc.registry.RegistryFactory;
import org.xiaoyu.rpc.client.RpcClientProxy;

import java.lang.reflect.Field;
import java.util.Properties;
import static org.xiaoyu.rpc.config.PropertiesConfig.properties;

/**
 * Created By Have
 * 2021/7/13 20:53
 */
@Component
public class RpcClientBeanProxyPostProcessor implements InstantiationAwareBeanPostProcessor {
    private static final RegistryFactory registry = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getExtension("nacosRegistryFactory");
    private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension();
    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getDefaultExtension();
    /**
     * 无法注入 由于这也是个PostProcessor会被先初始化 我的spring框架是一次性将所有BeanPostProcessor初始化完成后再加入处理链
     * 这里就默认赋值吧，后续等对他进行改进再说
     */
//    @Value(value = "${registryAddr}")
    private String serverAddr = properties.getProperty(SystemPropertiesKey.REGISTER_ADDR);
//    @Value(value = "${namespace}")
    private String namespace = properties.getProperty(SystemPropertiesKey.NAMESPACE) == null? "public": properties.getProperty(SystemPropertiesKey.NAMESPACE);
//    @Value(value = "${host}")
    private String host = properties.getProperty(SystemPropertiesKey.SERVER_HOST);
//    @Value(value = "${port}")
    private int port = Integer.valueOf(properties.getProperty(SystemPropertiesKey.SERVER_PORT));

    /**
     * 1. 将其注册到Protocol
     * 2. 将其注册到注册中心
     * @param aClass
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> aClass, String beanName) throws BeansException {
        return null;
    }


    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues psv, Object bean, String beanName) throws BeansException {
        return psv;
    }

    /**
     * modifiy RpcReference
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        RpcService rpcService = bean.getClass().getAnnotation(RpcService.class);
        if (rpcService != null) {
            String group = rpcService.group();
            Class<?> clazz = rpcService.interfaceClass();
            String serviceName = rpcService.serviceName();
            String path = rpcService.path();
            String version = rpcService.version();
            float weight = rpcService.weight();
            URL url = URL.builder()
                    .group(group)
                    .path(path)
                    .serviceName(serviceName)
                    .interfaceClass(clazz)
                    .version(version)
                    .weight(weight)
                    .host(host)
                    .port(port)
                    .build();
            Properties properties = new Properties();
            properties.put(SystemPropertiesKey.REGISTER_ADDR, serverAddr);
            properties.put(SystemPropertiesKey.NAMESPACE, namespace);
            Registry registry = RpcClientBeanProxyPostProcessor.registry.createRegistry(properties);
            System.out.println(properties);
            Invoker<?> invoker = proxyFactory.getInvoker(bean, clazz, url);
            registry.register(url);
            protocol.export(invoker);
        }

        Field[] fields = bean.getClass().getFields();
        for (Field field : fields) {
            RpcReference annotation = field.getAnnotation(RpcReference.class);
            if (annotation != null) {
                String group = annotation.group();
                String serviceName = annotation.serviceName();
                String version = annotation.version();
                String path = annotation.path();
                Class<?> aClass = annotation.interfaceClass();
                boolean async = annotation.isAsync();
                URL url = URL.builder()
                        .version(version)
                        .group(group)
                        .serviceName(serviceName)
                        .path(path)
                        .interfaceClass(aClass)
                        .async(async)
                        .build();
                ClientHandler instance = SingletonFactory.getInstance(ClientHandler.class);
                RpcClientProxy rpcClientProxy = new RpcClientProxy(instance, url);
                Object proxy = rpcClientProxy.getProxy(field.getType());
                field.setAccessible(true);
                try {
                    field.set(bean, proxy);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}
